home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Snippets / Stuart's Tech Notes / Stu’sThreadUtils / ThreadSynch.c < prev    next >
Encoding:
Text File  |  1994-03-19  |  3.7 KB  |  146 lines  |  [TEXT/KAHL]

  1. // ThreadSynch.c
  2. // 
  3. // Copyright (C) 6th March 1994  Stuart Cheshire <cheshire@cs.stanford.edu>
  4. //
  5. // See ThreadSynch.h for usage instructions.
  6.  
  7. #include "ThreadSynch.h"
  8. struct SemaphoreWaiter { SemaphoreWaiter *next; ThreadID ID; };
  9. struct ConditionWaiter { ConditionWaiter *next; Semaphore sem; };
  10.  
  11. // *****************************************************************
  12. // Semaphore. Operations: Init, Proben (test), Verhogen (increment)
  13.  
  14. void SemaphoreInit(Semaphore *s, long initialvalue)
  15.     {
  16.     s->value = initialvalue;
  17.     s->head = NULL;
  18.     s->tail = &s->head;
  19.     }
  20.  
  21. void SemaphoreP(Semaphore *s)
  22.     {
  23.     ThreadBeginCritical();
  24.     if (s->value > 0)        // If resource available, consume and continue
  25.         {
  26.         s->value--;
  27.         ThreadEndCritical();
  28.         }
  29.     else                    // else queue up and sleep
  30.         {
  31.         SemaphoreWaiter me;
  32.         me.next = NULL;
  33.         GetCurrentThread(&me.ID);
  34.         *(s->tail) = &me;
  35.         s->tail = &me.next;
  36.         SetThreadStateEndCritical(kCurrentThreadID, kStoppedThreadState, kNoThreadID);
  37.         }
  38.     }
  39.  
  40. void SemaphoreV(Semaphore *s)
  41.     {
  42.     ThreadBeginCritical();
  43.     if (!s->head)            // If no waiters, increment resource count
  44.         {
  45.         s->value++;
  46.         ThreadEndCritical();
  47.         }
  48.     else                    // else wake up one of the waiters
  49.         {
  50.         SemaphoreWaiter *w = s->head;
  51.         s->head = s->head->next;
  52.         if (!s->head) s->tail = &s->head;
  53.         SetThreadStateEndCritical(w->ID, kReadyThreadState, kNoThreadID);
  54.         }
  55.     }
  56.  
  57.  
  58. // *****************************************************************
  59. // MutexLock. Operations: Init, Acquire, Release
  60.  
  61. void MutexLockInit(MutexLock *m)
  62.     {
  63.     SemaphoreInit(&m->sem, 1);
  64.     m->lockholder = kNoThreadID;
  65.     }
  66.  
  67. void MutexLockAcquire(MutexLock *m)
  68.     {
  69.     ThreadID currentThread;
  70.     GetCurrentThread(¤tThread);
  71.     if (m->lockholder == currentThread)
  72.         DebugStr("\pError: Deadlock: Attempt to reaquire lock already held");
  73.     SemaphoreP(&m->sem);
  74.     m->lockholder = currentThread;
  75.     }
  76.  
  77. void MutexLockRelease(MutexLock *m)
  78.     {
  79.     ThreadID currentThread;
  80.     GetCurrentThread(¤tThread);
  81.     if (m->lockholder != currentThread)
  82.         DebugStr("\pError: Thread releasing lock does not hold it");
  83.     m->lockholder = kNoThreadID;
  84.     SemaphoreV(&m->sem);
  85.     }
  86.  
  87.  
  88. // *****************************************************************
  89. // ConditionVar. Operations: Init, Wait, Signal, Broadcast
  90.  
  91. void ConditionVarInit(ConditionVar *c, MutexLock *lock)
  92.     {
  93.     c->lock = lock;
  94.     c->head = NULL;
  95.     c->tail = &c->head;
  96.     }
  97.  
  98. void ConditionVarWait(ConditionVar *c)
  99.     {
  100.     ConditionWaiter me;
  101.     ThreadID currentThread;
  102.     GetCurrentThread(¤tThread);
  103.     if (c->lock->lockholder != currentThread)
  104.         DebugStr("\pError: Thread waiting on condition variable does not hold correct lock");
  105.  
  106.     me.next = NULL;
  107.     SemaphoreInit(&me.sem, 0);
  108.     *(c->tail) = &me;
  109.     c->tail = &me.next;
  110.     MutexLockRelease(c->lock);
  111.     SemaphoreP(&me.sem);
  112.     MutexLockAcquire(c->lock);
  113.     }
  114.  
  115. void ConditionVarSignal(ConditionVar *c)
  116.     {
  117.     ThreadID currentThread;
  118.     GetCurrentThread(¤tThread);
  119.     if (c->lock->lockholder != currentThread)
  120.         DebugStr("\pError: Thread signalling condition variable does not hold correct lock");
  121.     if (c->head)                    // If there is someone waiting
  122.         {
  123.         SemaphoreV(&c->head->sem);    // Wake them up
  124.         c->head = c->head->next;    // And remove them from the list
  125.         if (!c->head) c->tail = &c->head;
  126.         }
  127.     }
  128.  
  129. void ConditionVarBroadcast(ConditionVar *c)
  130.     {
  131.     ThreadID currentThread;
  132.     GetCurrentThread(¤tThread);
  133.     if (c->lock->lockholder != currentThread)
  134.         DebugStr("\pError: Thread signalling condition variable does not hold correct lock");
  135.     while (c->head)                    // For every waiter in list
  136.         {
  137.         SemaphoreV(&c->head->sem);    // Wake them up
  138.         c->head = c->head->next;    // And remove them from the list
  139.         }
  140.     c->tail = &c->head;
  141.     }
  142.  
  143. // Note: We do not have to worry here about new waiters joining the end
  144. // of the queue while we are processing it because they can't join unless
  145. // they hold the correct lock -- and they can't because we have it.
  146.